/**
 *@File XMLFileWriteReadMain.cpp
 *
 *@Author: Bob
 *
 *@Create Time: 2017-1-15 23:12:25
 *
 *@Last Modify: Bob
 *
 *@Last Modify Time: 2017-1-15 23:12:25
 *
 *@Description:
 *	rapidxml生成和解析xml文件
 *	rapidxml包含四个头文件：
 *	rapidxml.hpp
 *		rapidxml的主要文件，实现内存池，解析string和异常处理
 *		实现xml_base(基数节点类) xml_attribute(文本类) xml_noe(节点类) xml_document(文档类)
 *	rapidxml_iterators.hpp
 *		提供两个迭代器：node_iterator, attribute_iterator
 *	rapidxml_print.hpp
 *		提供根字符串，流对象的转换函数
 *	rapidxml_utils.hpp
 *		提供一个file来读取文件使用
 *		提供两个计数函数count_children, count_attributes
 */

#include <iostream>
#include <string>
#include <rapidxml/rapidxml.hpp>
//#include <rapidxml/rapidxml_iterators.hpp>
#include <rapidxml/rapidxml_print.hpp>
#include <rapidxml/rapidxml_utils.hpp>

// 内存池大小
// RAPIDXML_STATIC_POOL_SIZE (64 * 1024)


#if 0
<? xml version = '1.0' encoding = 'utf-8' ?>
<config>
	<color>
		<red>0.1</red>
		<green>0.1</green>
		<blue>0.1</blue>
		<alpha>1.0</alpha>
	</color>
	<size>
		<x>640</x>
		<y>480</y>
	</size>
	<mode fullscreen = "false">screen mode</mode>
	<baidu href = "http://www.baidu.com">百度公司</baidu>
</config>
#endif


void GenerateXMLFile(std::string strFilePath)
{
	rapidxml::xml_document<> doc;
	rapidxml::xml_node<>* rootNode = doc.allocate_node(rapidxml::node_pi, doc.allocate_string("xml version='1.0' encoding='utf-8'"));
	if (rootNode != NULL)
	{
		doc.append_node(rootNode);
		rapidxml::xml_node<>* configNode = doc.allocate_node(rapidxml::node_element, "config", "information");
		if (configNode != NULL)
		{
			doc.append_node(configNode);
			rapidxml::xml_node<>* colorNode = doc.allocate_node(rapidxml::node_element, "color", NULL);
			if (colorNode != NULL)
			{
				configNode->append_node(colorNode);
				colorNode->append_node(doc.allocate_node(rapidxml::node_element, "red", "0.1"));
				colorNode->append_node(doc.allocate_node(rapidxml::node_element, "green", "0.1"));
				colorNode->append_node(doc.allocate_node(rapidxml::node_element, "blue", "0.1"));
				colorNode->append_node(doc.allocate_node(rapidxml::node_element, "alpha", "1.0"));
			}

			rapidxml::xml_node<>* sizeNode = doc.allocate_node(rapidxml::node_element, "size", NULL);
			if (sizeNode != NULL)
			{
				sizeNode->append_node(doc.allocate_node(rapidxml::node_element, "x", "640"));
				sizeNode->append_node(doc.allocate_node(rapidxml::node_element, "y", "480"));
				configNode->append_node(sizeNode);
			}
			
			rapidxml::xml_node<>* modeNode = doc.allocate_node(rapidxml::node_element, "mode", "screen mode");
			if (modeNode != NULL)
			{
				modeNode->append_attribute(doc.allocate_attribute("fullscreen", "false"));
				configNode->append_node(modeNode);
			}

			rapidxml::xml_node<> *comNode = doc.allocate_node(rapidxml::node_element, "baidu", "百度公司");
			if (comNode != NULL)
			{
				rapidxml::xml_attribute<> *attr = doc.allocate_attribute("href", "http://www.baidu.com");
				if (attr != NULL)
				{
					comNode->append_attribute(attr);
				}

				configNode->append_node(comNode);
			}
		}

		std::string strData;
		rapidxml::print(std::back_inserter(strData), doc, 0);
		std::cout << strData << std::endl;

		std::ofstream outFile(strFilePath, std::ios::out);
		if (outFile.is_open())
		{
			outFile << doc;
			outFile.close();
		}
	}
}


void ReadXMLFromFile(std::string strFilePath)
{
	rapidxml::file<> docFile(strFilePath.c_str());
	rapidxml::xml_document<> doc;
	doc.parse<0>(docFile.data());
	std::cout << doc.name() << std::endl;

	rapidxml::xml_node<> *rootNode = doc.first_node();
	if (rootNode != NULL)
	{
		std::cout << rootNode->name() << std::endl;

		// 遍历node
		rapidxml::xml_node<> *pNode1 = rootNode->first_node();
		if (pNode1 != NULL)
		{
			std::cout << "\t" << pNode1->name() << std::endl;
			rapidxml::xml_node<> *pNode11 = pNode1->first_node();
			for (; pNode11 != NULL; pNode11 = pNode11->next_sibling())
			{
				std::cout << "\t\t" << pNode11->name() << " " << pNode11->value() << std::endl; 
			}
		}

		pNode1 = pNode1->next_sibling();
		if (pNode1 != NULL)
		{
			std::cout << "\t" << pNode1->name() << std::endl;
			rapidxml::xml_node<> *pNode11 = pNode1->first_node();
			for (; pNode11 != NULL; pNode11 = pNode11->next_sibling())
			{
				std::cout << "\t\t" << pNode11->name() << " " << pNode11->value() << std::endl;
			}
		}

		// 遍历attribute
		pNode1 = pNode1->next_sibling();
		if (pNode1 != NULL)
		{
			std::cout << "\t" << pNode1->name() << std::endl;
			rapidxml::xml_attribute<>* pAttr = pNode1->first_attribute();
			for (; pAttr != NULL; pAttr = pAttr->next_attribute())
			{
				std::cout << "\t\t" << pAttr->name() << " " << pAttr->value() << std::endl;
			}
		}

		pNode1 = pNode1->next_sibling();
		if (pNode1 != NULL)
		{
			std::cout << "\t" << pNode1->name() << std::endl;
			rapidxml::xml_attribute<>* pAttr = pNode1->first_attribute();
			for (; pAttr != NULL; pAttr = pAttr->next_attribute())
			{
				std::cout << "\t\t" << pAttr->name() << " " << pAttr->value() << std::endl;
			}
		}
	}
}

// Mac OSX下的版本信息文件 /System/Library/CoreServices/SystemVersion.plist
std::string GetMacOSVersion(std::string strFilePath)
{
	std::string strMacOSVersion;
	std::string strTmp;
	rapidxml::file<> docFile(strFilePath.c_str());
	rapidxml::xml_document<> doc;
	doc.parse<0>(docFile.data());

	rapidxml::xml_node<> *pRootNode = doc.first_node(); //plist
	if (pRootNode != NULL)
	{
		rapidxml::xml_node<> *pdictNode = pRootNode->first_node(); // dict
		if (pdictNode != NULL)
		{
			pdictNode = pdictNode->first_node();
			for (; pdictNode != NULL; pdictNode = pdictNode->next_sibling())
			{
				strTmp = pdictNode->value();
				if (strTmp.compare("ProductName") == 0)
				{
					if (pdictNode->next_sibling() != NULL)
					{
						strMacOSVersion += pdictNode->next_sibling()->value();
					}
				}
				else if (strTmp.compare("ProductUserVisibleVersion") == 0)
				{
					if (pdictNode->next_sibling() != NULL)
					{
						strMacOSVersion = strMacOSVersion + " " + pdictNode->next_sibling()->value();
						break;
					}
				}
			}
		}
	}

	return strMacOSVersion;
}



void Parse(std::string strFilePath)
{
    rapidxml::file<> docFile(strFilePath.c_str());
	rapidxml::xml_document<> doc;
	doc.parse<0>(docFile.data());

	rapidxml::xml_node<> *pNode = doc.first_node();
	for (; pNode != NULL; pNode = pNode->next_sibling())
	{
		std::cout << pNode->name() << std::endl;
		for (rapidxml::xml_node<> *pChildNode = pNode->first_node(); pChildNode != NULL; pChildNode = pChildNode->next_sibling())
		{
			std::cout << " " << pChildNode->name() << " " << pChildNode->value() << std::endl;
		}
	}
}


void ParseWithAtrribute(std::string strFilePath /*= "1.xml"*/)
{
    rapidxml::file<> docFile(strFilePath.c_str());
    rapidxml::xml_document<> doc;
    doc.parse<0>(docFile.data());

    rapidxml::xml_node<> *pRootNode = doc.first_node();
    if (pRootNode != NULL)
    {
        std::cout << pRootNode->name() << " " << pRootNode->value()<< std::endl; // protocol
        rapidxml::xml_attribute<> *pAttr = pRootNode->first_attribute();
        if (pAttr != NULL)
        {
            std::cout << pAttr->name() << " " << pAttr->value() << std::endl; // version
        }

        rapidxml::xml_node<> *pChildNode = pRootNode->first_node();
        if (pChildNode != NULL)
        {
            std::cout << pChildNode->name() << " " << pChildNode->value() << std::endl;
            rapidxml::xml_node<> * pSonNode = pChildNode->first_node();
            for(; pSonNode != NULL; pSonNode = pSonNode->next_sibling())
            {
                std::cout << pSonNode->name() << " " << pSonNode->value() << std::endl; 
                rapidxml::xml_attribute<> *pSonAttr = pSonNode->first_attribute();
                if (pSonAttr != NULL)
                {
                    std::cout << "  " << pSonAttr->name() << ":" << pSonAttr->value() << std::endl;
                }   
            }
        }
    }
}


void ParseWithAtrribute()
{
    std::string str("<?xml version=\"1.0\" encoding=\"utf-8\"?> <protocol version=\"1.5\"> <srvResponse> <dateTime>2016-10-18T08:51:50.657+01:00</dateTime> <responseFrom ag=\"1\"/> <idMessage>0</idMessage> <rejectionCode>0</rejectionCode> </srvResponse> </protocol>");
    rapidxml::xml_document<> doc;
    doc.parse<0>((char *)(str.c_str()));

    rapidxml::xml_node<> *pRootNode = doc.first_node();
    if (pRootNode != NULL)
    {
        std::cout << pRootNode->name() << " " << pRootNode->value() << std::endl; // protocol
        rapidxml::xml_attribute<> *pAttr = pRootNode->first_attribute();
        if (pAttr != NULL)
        {
            std::cout << pAttr->name() << " " << pAttr->value() << std::endl; // version
        }

        rapidxml::xml_node<> *pChildNode = pRootNode->first_node();
        if (pChildNode != NULL)
        {
            std::cout << pChildNode->name() << " " << pChildNode->value() << std::endl;
            rapidxml::xml_node<> * pSonNode = pChildNode->first_node();
            for (; pSonNode != NULL; pSonNode = pSonNode->next_sibling())
            {
                std::cout << pSonNode->name() << " " << pSonNode->value() << std::endl;
                rapidxml::xml_attribute<> *pSonAttr = pSonNode->first_attribute();
                if (pSonAttr != NULL)
                {
                    std::cout << "  " << pSonAttr->name() << ":" << pSonAttr->value() << std::endl;
                }
            }
        }
    }
}



int main(int argc, char *argv[])
{
// http://longma2006.blog.51cto.com/883421/1076720
// http://www.cnblogs.com/kanego/articles/2247602.html
// http://blog.csdn.net/wqvbjhc/article/details/7662931
// http://blog.sina.com.cn/s/blog_9b0604b40101o6fm.html
// http://www.oschina.net/question/873634_81784

	GenerateXMLFile("../Output/config.xml");
	ReadXMLFromFile("../Output/config.xml");

	std::string strVersion = GetMacOSVersion("../Output/SystemVersion.plist");
	if (!strVersion.empty())
	{
		std::cout << "Mac OSX Version: " << strVersion << std::endl;
	}

    Parse("../Output/1.txt");
    ParseWithAtrribute("../Output/2.txt");
    ParseWithAtrribute();
	return 0;
}